//
// Created by 李传智 on 2018/5/1.
//

#include "FFRecorder.h"
#include "Logger.h"

bool FFRecorder::open(const char *url, CodecParameter outAudioParam, CodecParameter outVideoParam) {
    close();
    AVOutputFormat *fmt = av_guess_format(NULL, url, NULL);
    mutex.lock();
    // 获取输出格式上下文
    if (avformat_alloc_output_context2(&fmtContext, fmt, NULL, url) != 0) {
        LOG_E("avformat_alloc_output_context2 failed");
        mutex.unlock();
        return false;
    }
    // 添加音频流
    AVCodec *audioCodec = avcodec_find_encoder(outAudioParam.parameters->codec_id);
    if (!audioCodec) {
        LOG_E("audio avcodec_find_encoder failed");
        mutex.unlock();
        return false;
    }
    AVStream *audioStream = avformat_new_stream(fmtContext, audioCodec);
    if (!audioStream) {
        LOG_E("audio avformat_new_stream failed");
        mutex.unlock();
        return false;
    }
    avcodec_parameters_copy(audioStream->codecpar, outAudioParam.parameters);
    AVCodec *videoCodec = avcodec_find_encoder(outVideoParam.parameters->codec_id);
    if (!videoCodec) {
        LOG_E("video avcodec_find_encoder failed");
        mutex.unlock();
        return false;
    }
    // 添加视频流
    AVStream *videoStream = avformat_new_stream(fmtContext, videoCodec);
    if (!videoStream) {
        LOG_E("video avformat_new_stream failed");
        mutex.unlock();
        return false;
    }
    avcodec_parameters_copy(videoStream->codecpar, outVideoParam.parameters);
    LOG_I("FFRecorder nb_steams = %d", fmtContext->nb_streams);
    // 打开输出文件
    if (avio_open(&fmtContext->pb, url, AVIO_FLAG_WRITE) < 0) {
        LOG_E("avio_open failed");
        mutex.unlock();
        return false;
    }
    // 写入视频文件头
    if (avformat_write_header(fmtContext, NULL) < 0) {
        LOG_E("avformat_write_header failed");
        mutex.unlock();
        return false;
    }
    mutex.unlock();
}

bool FFRecorder::record(VideoData data) {
    mutex.lock();
    if (isFirst) {
        isFirst = false;
        if (data.isAudio) {
            audioPts = data.pts;
        } else {
            videoPts = data.pts;
        }
    }
    AVPacket *pkt = (AVPacket *) data.data;
    pkt->dts = pkt->pts = pkt->pts - (data.isAudio ? audioPts : videoPts);
    pkt->stream_index = data.isAudio ? 0 : 1;
    // 向输出流写入一个分包数据
    av_interleaved_write_frame(fmtContext, pkt);
    mutex.unlock();
}

bool FFRecorder::close() {
    IRecorder::clear();
    mutex.lock();
    isFirst = true;
    audioPts = videoPts = 0;
    if (fmtContext) {
        // 写输出流的文件尾
        av_write_trailer(fmtContext);
        avio_close(fmtContext->pb);
        avformat_free_context(fmtContext);
        fmtContext = NULL;
    }
    mutex.unlock();
}

